package com.sunky.rfidapp.network;

import android.util.Log;

import com.google.gson.Gson;
import com.sunky.rfidapp.util.JsonUtil;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import io.reactivex.annotations.Nullable;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import okio.Buffer;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

/**
 * Created by stan on 2018/3/13.
 */

public class NetBuilder {
    public static String sUrl = "";
    public static String sCode = "";
    private static int defaultTimeout = 60; //超时时间
    private static TimeUnit defaultUnit = TimeUnit.SECONDS; //单位秒

    /***************************公共参数 start****************************/
    private static String USER_ID = "userId"; //用户ID
    private static String WAREHOUSE_NO = "warehouseNo"; //货仓code
    private static String TOKEN = "token"; //token

    /***************************公共参数  end*****************************/

    private static volatile NetBuilder instance = null;
    private Retrofit retrofit;

    private NetBuilder() {
        retrofit = createRetrofit();
    }

    public Retrofit getRetrofit() {
        return retrofit;
    }

    private Gson gson = new Gson();

    /**
     * 刷新retrofit
     */
    public void refreshRetrofit() {
        retrofit = createRetrofit();
    }

    public static NetBuilder getInstance() {
        if (null == instance) {
            synchronized (NetBuilder.class) {
                if (null == instance) {
                    instance = new NetBuilder();
                }
            }
        }
        return instance;
    }

    private Retrofit createRetrofit() {

        return new Retrofit.Builder()
                .client(createClient())
                .baseUrl(getRealUrl())
                .addConverterFactory(new Converter.Factory() {
                    @Nullable
                    @Override
                    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
                        return new Converter<ResponseBody, Object>() {
                            @Override
                            public Object convert(ResponseBody value) throws IOException {
                                try {
                                    return value.string();
                                } finally {
                                    value.close();
                                }
                            }
                        };
                    }

                    @Nullable
                    @Override
                    public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
                        return new Converter<String, RequestBody>() {
                            @Override
                            public RequestBody convert(String value) throws IOException {
                                Buffer buffer = new Buffer();
                                Writer writer = new OutputStreamWriter(buffer.outputStream(), Charset.forName("UTF-8"));
                                writer.write(value);
                                writer.close();
                                return RequestBody.create(MediaType.parse("application/json; charset=UTF-8"), buffer.readByteString());
                            }
                        };
                    }

                    @Nullable
                    @Override
                    public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
                        return super.stringConverter(type, annotations, retrofit);
                    }
                })
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //需要检查
                .build();
    }

    private static String getRealUrl() {
        if (!sUrl.endsWith("/")){
            sUrl += "/";
        }
        return "http://"+sUrl;
    }

    private static OkHttpClient createClient() {
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
//                LocalLog.e(message);
                Log.e("request",message);
            }
        });
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); //日志输出

        return new OkHttpClient.Builder()
                .addInterceptor(REWRITE_NET_INTERCEPTOR)
                .addNetworkInterceptor(httpLoggingInterceptor) //日志输出拦截器
                .connectTimeout(defaultTimeout, defaultUnit)
                .readTimeout(defaultTimeout, defaultUnit)
                .writeTimeout(defaultTimeout, defaultUnit)
                .build(); //设置d默认超时时间
    }

    private final static Interceptor REWRITE_NET_INTERCEPTOR = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request(); //原始请求
            if (request.method().equals("GET")) {
                request = addGetParams(request);
            } else if (request.method().equals("POST")) {
                request = addPostParams(request);
            }
            return chain.proceed(request);
        }
    };

    //get请求 添加公共参数 签名
    private static Request addGetParams(Request request) {
        //添加公共参数
        HttpUrl httpUrl = request.url()
                .newBuilder()
//                .addQueryParameter(USER_ID, AccountInfo.INSTANCE.getUserId())
//                .addQueryParameter(WAREHOUSE_NO, AccountInfo.INSTANCE.getWarehouseNo())
//                .addQueryParameter(TOKEN, AccountInfo.INSTANCE.getToken())
                .build();
//        LogUtil.logd("URL", "URL REQ GET:" + httpUrl);
        request = request.newBuilder().url(httpUrl).build();
        return request;
    }

    //post 添加签名和公共参数
    private static Request addPostParams(Request request) {
        if (request.body() instanceof FormBody) { //考虑的是post formUrlEncode方式传入的是Map参数
            FormBody.Builder bodyBuilder = new FormBody.Builder();
            FormBody formBody = (FormBody) request.body();
            if (null != formBody) {
                //把原来的参数添加到新的构造器，（因为没找到直接添加，所以就new新的）
                for (int i = 0; i < formBody.size(); i++) {
                    bodyBuilder.addEncoded(formBody.encodedName(i), formBody.encodedValue(i));
                }
            }
            formBody = bodyBuilder
//                    .addEncoded(USER_ID, AccountInfo.INSTANCE.getUserId())
//                    .addEncoded(WAREHOUSE_NO, AccountInfo.INSTANCE.getWarehouseNo())
//                    .addEncoded(TOKEN, AccountInfo.INSTANCE.getToken())
                    .build();
            request = request
                    .newBuilder()
                    .post(formBody)
                    .build();
        } else { //考虑的是@body 传入的是Json格式
            String reqBodyStr = bodyToString(request.body()); //原始入参
            // 所有请求参数加上sessionId （如果sessionId不为空）
            Map<String, Object> map = JsonUtil.toJsonObject(reqBodyStr, Map.class);
            if (map != null) {
//                map.put(USER_ID, AccountInfo.INSTANCE.getUserId());
//                map.put(TOKEN, AccountInfo.INSTANCE.getToken());
//                map.put(WAREHOUSE_NO, AccountInfo.INSTANCE.getWarehouseNo());
                reqBodyStr = JsonUtil.toJson(map);
            }
            RequestBody requestBody = RequestBody.create(request.body().contentType(), reqBodyStr);
//            LogUtil.logd("URL", "URL REQ POST URL" + request.url() + "; JSON:" + reqBodyStr);
            request = request
                    .newBuilder()
                    .method(request.method(), requestBody)
                    .build();
        }
        return request;
    }

    private static String bodyToString(final RequestBody request) {
        try {
            final Buffer buffer = new Buffer();
            if (request != null)
                request.writeTo(buffer);
            else
                return "";
            return buffer.readUtf8();
        } catch (final IOException e) {
            return "did not work";
        }
    }
}
